
package com.jf.cloud.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.jf.cloud.api.delivery.dto.DeliveryOrderDTO;
import com.jf.cloud.api.delivery.dto.DeliveryOrderItemDTO;
import com.jf.cloud.api.delivery.feign.DeliveryFeignClient;
import com.jf.cloud.api.delivery.vo.DeliveryCompanyExcelVO;
import com.jf.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.jf.cloud.api.multishop.vo.ShopDetailVO;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.order.constant.DeliveryType;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.ExcelUtil;
import com.jf.cloud.common.util.PrincipalUtil;
import com.jf.cloud.order.constant.OrderExportError;
import com.jf.cloud.order.constant.PurchasesStatusEnum;
import com.jf.cloud.order.constant.RefundStatusEnum;
import com.jf.cloud.order.dto.PurchaseOrderDTO;
import com.jf.cloud.order.listener.PurchaseOrderInboundExcelListener;
import com.jf.cloud.order.mapper.PurchaseOrderMapper;
import com.jf.cloud.order.model.OrderAddr;
import com.jf.cloud.order.service.OrderAddrService;
import com.jf.cloud.order.service.PurchaseOrderExcelService;
import com.jf.cloud.order.service.PurchaseOrderService;
import com.jf.cloud.order.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采购订单
 *
 * @author zz
 * @date 2022-06-22 17:12:02
 */
@Service
public class PurchaseOrderExcelServiceImpl implements PurchaseOrderExcelService {

    @Value("${jfcloud.expose.operation.auth:}")
    private Boolean permission;
    @Autowired
    private PurchaseOrderMapper purchaseOrderMapper;
    @Autowired
    private OrderAddrService orderAddrService;
    @Autowired
    private PurchaseOrderService purchaseOrderService;
    @Autowired
    private DeliveryFeignClient deliveryFeignClient;
    @Autowired
    private ShopDetailFeignClient shopDetailFeignClient;

    /**
     * 配送类型
     */
    public final static int DELIVERY_MODE_INDEX = 2;

    /**
     * 快递公司名称
     */
    public final static int DELIVERY_COMPANY_NAME_INDEX = 3;

    private final static int FLOW_ID_MIN = 4;
    private final static int FLOW_ID_MAX = 30;

    public final static String[] DELIVERY_MODE = {DeliveryType.DELIVERY.description(), DeliveryType.NOT_DELIVERY.description()};

    private static final Logger log = LoggerFactory.getLogger(OrderExcelServiceImpl.class);

    @Override
    public List<PurchaseOrderExcelVO> excelOrderList(PurchaseOrderDTO purchaseOrderDTO) {
        ServerResponseEntity<List<ShopDetailVO>> shopResp = shopDetailFeignClient.getShopDetailByShopIdAndShopName(purchaseOrderDTO.getShopName());
        if (!shopResp.isSuccess()) {
            throw new LuckException(shopResp.getMsg());
        }
        List<Long> shopIds = shopResp.getData().stream().map(ShopDetailVO::getShopId).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(shopIds)){
            shopIds.add(-1L);
        }
        List<PurchaseOrderExcelVO> purchaseOrderList = purchaseOrderMapper.listPurchaseOrderDetail(purchaseOrderDTO, null, shopIds);
        int index = 0;
        Long orderId = null;
        for (PurchaseOrderExcelVO orderExcel : purchaseOrderList) {
            if (!Objects.equals(Long.valueOf(orderExcel.getPurchaseOrderId()), orderId)) {
                index++;
                orderId = Long.valueOf(orderExcel.getPurchaseOrderId());
            }
            orderExcel.setSeq(String.valueOf(index));
            // 订单信息
            Integer deliveryType = Integer.valueOf(orderExcel.getDeliveryType());
            orderExcel.setDeliveryType(DeliveryType.getDescription(deliveryType));
            orderExcel.setTotalAmount(conversionPrices(orderExcel.getTotalAmount()));
//            orderExcel.setFreightAmount(conversionPrices(orderExcel.()));
            String payType = Constant.OFFLINE_PAID;
            orderExcel.setPayType(payType);
            //收货手机号
            if (BooleanUtil.isFalse(permission)) {
                orderExcel.setMobile(PhoneUtil.hideBetween(orderExcel.getMobile()).toString());
            }
            orderExcel.setStatus(PurchasesStatusEnum.getStatusName(Integer.valueOf(orderExcel.getStatus())));
            // 订单项信息
            orderExcel.setPurchasePrice(conversionPrices(orderExcel.getPurchasePrice()));
            orderExcel.setPurchaseAmount(conversionPrices(orderExcel.getPurchaseAmount()));
            // 国际化信息
            Map<Integer, PurchaseOrderItemLangVO> spuNameMap = orderExcel.getOrderItemLangList().stream().collect(Collectors.toMap(PurchaseOrderItemLangVO::getLang, o -> o));
            PurchaseOrderItemLangVO orderItemLangVO = spuNameMap.get(I18nMessage.getLang());
            if (Objects.isNull(orderItemLangVO)) {
                orderItemLangVO = spuNameMap.get(Constant.DEFAULT_LANG);
            }
//            PurchaseOrderItemLangVO orderItemLangVO = OrderLangUtil.handleOrderItemLangVO(orderExcel.getOrderItemLangList());
            if (Objects.nonNull(orderItemLangVO)) {
                orderExcel.setSkuName(orderItemLangVO.getSkuName());
                orderExcel.setSpuName(orderItemLangVO.getSpuName());
            }
        }
        return purchaseOrderList;
    }

    @Override
    public void excelUnDeliveryOrderList(HttpServletResponse response, PurchaseOrderDTO purchaseOrderDTO) {
        ServerResponseEntity<List<ShopDetailVO>> shopResp = shopDetailFeignClient.getShopDetailByShopIdAndShopName(purchaseOrderDTO.getShopName());
        if (!shopResp.isSuccess()) {
            throw new LuckException(shopResp.getMsg());
        }
        List<Long> shopIds = shopResp.getData().stream().map(ShopDetailVO::getShopId).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(shopIds)){
            shopIds.add(-1L);
        }
        purchaseOrderDTO.setStatus(PurchasesStatusEnum.WAIT_STOCK.value());
        List<UnDeliveryPurchaseOrderExcelVO> purchaseOrderList = purchaseOrderMapper.listUnDeliveryPurchaseOrder(purchaseOrderDTO, null, shopIds);
        Map<Integer, String[]> map = new HashMap<>(8);
        map.put(DELIVERY_MODE_INDEX, DELIVERY_MODE);
        int index = 0;
        //合并单元格
        Long orderId = null;
        for (UnDeliveryPurchaseOrderExcelVO orderExcel : purchaseOrderList) {
            if (!Objects.equals(Long.valueOf(orderExcel.getPurchaseOrderId()), orderId)) {
                index++;
                orderId = Long.valueOf(orderExcel.getPurchaseOrderId());
            }
            orderExcel.setSeq(String.valueOf(index));
            //物流信息
            orderExcel.setDeliveryType(DeliveryType.getDescription(Integer.valueOf(orderExcel.getDeliveryType())));
            //快递公司名称
            map.put(DELIVERY_COMPANY_NAME_INDEX, getDeliveryCompanyName());

        }
        writeExcel(response, purchaseOrderList, map);
    }

    @Override
    public void exportOrderExcel(List<UnDeliveryPurchaseOrderExcelVO> list, Map<Integer, List<String>> errorMap) {
        List<DeliveryCompanyExcelVO> companyExcelList = deliveryFeignClient.listDeliveryCompany().getData();
        Map<String, Long> companyNameMap = companyExcelList.stream().collect(Collectors.toMap(DeliveryCompanyExcelVO::getName, DeliveryCompanyExcelVO::getDeliveryCompanyId));
        Map<String, List<UnDeliveryPurchaseOrderExcelVO>> orderMap = list.stream().collect(Collectors.groupingBy(UnDeliveryPurchaseOrderExcelVO::getSeq));
        for (String seq : orderMap.keySet()) {
            List<UnDeliveryPurchaseOrderExcelVO> orderExcels = orderMap.get(seq);
            DeliveryOrderDTO deliveryOrder = new DeliveryOrderDTO();
            try {
                loadOrderData(orderExcels, deliveryOrder, companyNameMap, errorMap);
            } catch (Exception e) {
                addOrderExcelError(errorMap, OrderExportError.OTHER, e.getMessage());
                continue;
            }
            if (Objects.nonNull(deliveryOrder.getSelectOrderItems())) {
                //订单发货
                purchaseOrderService.delivery(deliveryOrder);
            }
        }
    }

    @Override
    public String orderExportError(Map<Integer, List<String>> errorMap) {
        StringBuilder info = new StringBuilder();
        for (Integer key : errorMap.keySet()) {
            List<String> list = errorMap.get(key);
            OrderExportError orderExportError = OrderExportError.instance(key);
            if (Objects.equals(orderExportError, OrderExportError.OTHER)) {
                info.append(list.toString() + "\n");
                continue;
            }
            info.append(orderExportError.errorInfo() + list.toString() + "\n");
        }
        return info.toString();
    }

    @Override
    public List<PurchaseOrderItemVO> inboundParseFile(MultipartFile excelFile, Long shopId, Long purchaseOrderId) {
        List<PurchaseOrderInboundExcelVO> list = new ArrayList<>();
        Map<String, List<String>> errorMap = new HashMap<>(16);
        PurchaseOrderInboundExcelListener purchaseExcelListener = new PurchaseOrderInboundExcelListener(errorMap,list);
        // 获取数据库的采购订单信息，并转换成map
        PurchaseOrderVO purchaseOrderVO = purchaseOrderService.info(purchaseOrderId, null);
        List<PurchaseOrderItemVO> purchaseOrderItemList = purchaseOrderVO.getPurchaseOrderItemList();
        Map<String, PurchaseOrderItemVO> purchaseOrderItemMap = purchaseOrderItemList.stream()
                .filter(purchaseProd -> !Objects.equals(purchaseOrderVO.getStatus(), 0))
                .collect(Collectors.toMap(PurchaseOrderItemVO::getPartyCode, p -> p));
        try {
            EasyExcel.read(excelFile.getInputStream(), PurchaseOrderInboundExcelVO.class, purchaseExcelListener).sheet().doRead();
        } catch (IOException e) {
            throw new LuckException(e.getMessage());
        }
        if(CollectionUtil.isEmpty(list)){
            throw new LuckException("导入数据为空，请检查下文件");
        }
        for (PurchaseOrderInboundExcelVO purchaseOrderInboundExcelVO : list) {
            String partyCode = purchaseOrderInboundExcelVO.getPartyCode();
            if (StrUtil.isBlank(partyCode)) {
                throw new LuckException("商品编码不能为空");
            }
            if (!purchaseOrderItemMap.containsKey(partyCode)) {
                throw new LuckException("商品编码填写错误");
            }
            PurchaseOrderItemVO purchaseOrderItemVO = purchaseOrderItemMap.get(partyCode);
            purchaseOrderItemVO.setChangeStock(purchaseOrderInboundExcelVO.getBeDeliveredNum());
        }
        return purchaseOrderItemList;
    }

    private void loadOrderData(List<UnDeliveryPurchaseOrderExcelVO> orderExcels, DeliveryOrderDTO deliveryOrder, Map<String, Long> companyNameMap, Map<Integer, List<String>> errorMap) {

        // -------------------------------------------------------------
        UnDeliveryPurchaseOrderExcelVO orderExcel = orderExcels.get(0);
        //订单id不能为空且该订单必须为当前店铺的订单，并为待发货状态
        if (Objects.isNull(orderExcel.getPurchaseOrderId())) {
            addOrderExcelError(errorMap, OrderExportError.ORDER_ID, orderExcel.getSeq());
            return;
        }
        PurchaseOrderVO purchaseOrderVO = purchaseOrderService.info(Long.valueOf(orderExcel.getPurchaseOrderId()), null);
        if (Objects.isNull(purchaseOrderVO) || !Objects.equals(purchaseOrderVO.getStatus(), PurchasesStatusEnum.WAIT_STOCK.value())) {
            addOrderExcelError(errorMap, OrderExportError.ORDER_ID, orderExcel.getSeq());
            return;
        }
        List<PurchaseOrderItemVO> purchaseOrderItemList = purchaseOrderVO.getPurchaseOrderItemList();
        for (PurchaseOrderItemVO orderItemVO : purchaseOrderItemList) {
            if (Objects.equals(orderItemVO.getBeDeliveredNum(), 0) || !Objects.equals(orderItemVO.getBeDeliveredNum(), orderItemVO.getPurchaseStock())) {
                // 如果该订单已经被部分发货或全部发货则不予发货
                addOrderExcelError(errorMap, OrderExportError.BE_DELIVERY, orderExcel.getSeq());
                return;
            }
        }
        deliveryOrder.setOrderId(Long.valueOf(orderExcel.getPurchaseOrderId()));
        //配送方式不为空
        if (Objects.isNull(orderExcel.getDeliveryType())) {
            addOrderExcelError(errorMap, OrderExportError.DELIVERY_TYPE, orderExcel.getSeq());
            return;
        }
        if (Objects.equals(orderExcel.getDeliveryType(), DeliveryType.DELIVERY.description())) {
            deliveryOrder.setDeliveryType(DeliveryType.DELIVERY.value());
        } else if (Objects.equals(orderExcel.getDeliveryType(), DeliveryType.NOT_DELIVERY.description())) {
            deliveryOrder.setDeliveryType(DeliveryType.NOT_DELIVERY.value());
        }
        //订单的配送方式为快递配送时，导入的配送方式可选择快递配送和无需快递，其他情况订单的配送方式与导入的配送方式需保持一致
        if(!Objects.equals(deliveryOrder.getDeliveryType(), purchaseOrderVO.getDeliveryType()) &&  !Objects.equals(purchaseOrderVO.getDeliveryType(),  DeliveryType.DELIVERY.value() )){
            addOrderExcelError(errorMap, OrderExportError.DELIVERY_TYPE, orderExcel.getSeq());
            return;
        }else if(!Objects.equals(deliveryOrder.getDeliveryType(), purchaseOrderVO.getDeliveryType()) &&  Objects.equals(purchaseOrderVO.getDeliveryType(),  DeliveryType.DELIVERY.value() )){
            if(!Objects.equals(deliveryOrder.getDeliveryType(), DeliveryType.NOT_DELIVERY.value())){
                addOrderExcelError(errorMap, OrderExportError.DELIVERY_TYPE, orderExcel.getSeq());
                return;
            }
        }

        //只有快递才需要快递校验
        if (Objects.equals(orderExcel.getDeliveryType(), DeliveryType.DELIVERY.description())) {
            //快递公司校验
            if (Objects.isNull(orderExcel.getDeliveryCompanyName())) {
                addOrderExcelError(errorMap, OrderExportError.DELIVERY_COMPANY_NAME, orderExcel.getSeq());
                return;
            }
            deliveryOrder.setDeliveryCompanyId(companyNameMap.get(orderExcel.getDeliveryCompanyName()));
            //快递单号校验
            String deliveryNo = orderExcel.getDeliveryNo();
            deliveryNo = StringUtils.deleteWhitespace(deliveryNo);
            boolean isTrue = StrUtil.isBlank(deliveryNo) ||
                    (deliveryNo.length() > FLOW_ID_MAX || deliveryNo.length() < FLOW_ID_MIN)
                    || !PrincipalUtil.isMatching(PrincipalUtil.WITHOUT_CHINESE, deliveryNo);
            if (isTrue) {
                addOrderExcelError(errorMap, OrderExportError.DELIVERY_NO, orderExcel.getSeq());
                return;
            }
            deliveryOrder.setDeliveryNo(deliveryNo);
        }
        List<DeliveryOrderItemDTO> orderItemFeignVOList = new ArrayList<>();
        for (PurchaseOrderItemVO orderItemVO : purchaseOrderItemList) {
            DeliveryOrderItemDTO deliveryOrderItemFeignVO = new DeliveryOrderItemDTO();
            deliveryOrderItemFeignVO.setOrderItemId(orderItemVO.getPurchaseItemId());
            deliveryOrderItemFeignVO.setChangeNum(orderItemVO.getBeDeliveredNum());
            deliveryOrderItemFeignVO.setPic(orderItemVO.getPic());
            deliveryOrderItemFeignVO.setSpuName(orderItemVO.getSpuName());
            orderItemFeignVOList.add(deliveryOrderItemFeignVO);
        }
        deliveryOrder.setSelectOrderItems(orderItemFeignVOList);
        // 用户收货地址
        OrderAddr orderAddr = orderAddrService.getById(purchaseOrderVO.getPurchaseOrderAddrId());
        if (Objects.nonNull(orderAddr)) {
            deliveryOrder.setConsignee(orderAddr.getConsignee());
            deliveryOrder.setMobile(orderAddr.getMobile());
        }
    }

    private void addOrderExcelError(Map<Integer, List<String>> errorMap, OrderExportError orderExportError, String error) {
        List<String> list = errorMap.get(orderExportError.value());
        if (CollUtil.isEmpty(list)) {
            list = new ArrayList<>();
            errorMap.put(orderExportError.value(), list);
        }
        list.add(error);
    }

    /**
     * 转换金额格式
     *
     * @param num
     * @return
     */
    private String conversionPrices(String num) {
        if (StrUtil.isBlank(num)) {
            return num;
        }
        BigDecimal b1 = new BigDecimal(num);
        BigDecimal b2 = new BigDecimal(Constant.PRICE_MAGNIFICATION);
        double price = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
        return Double.toString(price);
    }

    private String[] getDeliveryCompanyName() {
        //快递公司名称
        ServerResponseEntity<List<DeliveryCompanyExcelVO>> companyData = deliveryFeignClient.listDeliveryCompany();
        if (!Objects.equals(companyData.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(companyData.getMsg());
        }
        List<DeliveryCompanyExcelVO> companyExcelList = companyData.getData();
        if (CollUtil.isNotEmpty(companyExcelList)) {
            String[] companyNames = new String[companyExcelList.size()];
            for (int i = 0; i < companyExcelList.size(); i++) {
                DeliveryCompanyExcelVO companyExcel = companyExcelList.get(i);
                companyNames[i] = companyExcel.getName();
            }
            return companyNames;
        }
        return null;
    }

    private void writeExcel(HttpServletResponse response, List<UnDeliveryPurchaseOrderExcelVO> list, Map<Integer, String[]> map) {
        ExcelWriter excelWriter = null;
        try {
            ExcelWriterBuilder excelWriterMerge = ExcelUtil.getExcelWriterMerge(response, UnDeliveryPurchaseOrderExcelVO.EXCEL_NAME, UnDeliveryPurchaseOrderExcelVO.MERGE_ROW_INDEX,
                    UnDeliveryPurchaseOrderExcelVO.MERGE_COLUMN_INDEX);
            excelWriter = ExcelUtil.getExcelModel(excelWriterMerge, map, Constant.START_ROW).build();
            //订单信息
            //写入
            WriteSheet writeSheet = EasyExcel.writerSheet(UnDeliveryPurchaseOrderExcelVO.EXCEL_NAME).head(UnDeliveryPurchaseOrderExcelVO.class).build();
            excelWriter.write(list, writeSheet);
        } catch (Exception e) {
            log.error("导出excel失败", e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}
